package com.niiwoo.civet.user.service.duboo;

import com.alibaba.dubbo.config.annotation.Reference;
import com.alibaba.dubbo.config.annotation.Service;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.niiwoo.activity.event.constant.BizEventRabbitConstant;
import com.niiwoo.activity.event.dto.request.CreditEventReqDTO;
import com.niiwoo.activity.event.enums.CreditTypeEventEnum;
import com.niiwoo.civet.account.dto.common.BankCardDTO;
import com.niiwoo.civet.account.dto.response.AccountBaseResponse;
import com.niiwoo.civet.account.enums.AccountActiveEnum;
import com.niiwoo.civet.account.service.AccountDubboService;
import com.niiwoo.civet.account.service.bankcard.BankCardDubboService;
import com.niiwoo.civet.trade.enums.ProjectStatusEnum;
import com.niiwoo.civet.trade.enums.TradeConfigEnum;
import com.niiwoo.civet.trade.service.ProjectCommonDubboService;
import com.niiwoo.civet.trade.service.configure.TradeConfigDubboService;
import com.niiwoo.civet.user.dao.aggregation.CreditDeviceInfo;
import com.niiwoo.civet.user.dao.entity.*;
import com.niiwoo.civet.user.dto.request.AFPCallbackDTO;
import com.niiwoo.civet.user.dto.request.LaunchSpeedLoanCreditRequestDTO;
import com.niiwoo.civet.user.dto.request.SpeedLoanCreditCallbackDTO;
import com.niiwoo.civet.user.dto.response.*;
import com.niiwoo.civet.user.enums.*;
import com.niiwoo.civet.user.service.UserCreditDubboService;
import com.niiwoo.civet.user.service.local.*;
import com.niiwoo.tripod.base.component.PrivacyMasks;
import com.niiwoo.tripod.base.utils.FutureResponses;
import com.niiwoo.tripod.base.utils.IdCardUtils;
import com.niiwoo.tripod.im.component.IMService;
import com.niiwoo.tripod.im.request.PushCommonNotifyMessageRequest;
import com.niiwoo.tripod.lanmao.enums.UserRoleEnum;
import com.niiwoo.tripod.provider.exception.BizException;
import com.niiwoo.tripod.service.component.SnowflakeIdWorker;
import com.niiwoo.tripod.tiancheng.component.TianchengQuantizationService;
import com.niiwoo.tripod.tiancheng.enums.CreditTypeEnum;
import com.niiwoo.tripod.tiancheng.enums.FunctionCodeEnum;
import com.niiwoo.tripod.tiancheng.enums.ModleResultEnum;
import com.niiwoo.tripod.tiancheng.request.afp.LoanAmountAgainsFakeRequest;
import com.niiwoo.tripod.tiancheng.request.df.CreditDataFlowRequest;
import com.niiwoo.tripod.tiancheng.request.qdp.EducationQueryRequest;
import com.niiwoo.tripod.tiancheng.request.qdp.MobileRealNameRequest;
import com.niiwoo.tripod.tiancheng.response.common.AgainstFakeResponse;
import com.niiwoo.tripod.tiancheng.response.common.EducationQueryResponse;
import com.niiwoo.tripod.tiancheng.response.common.MobileRealNameResponse;
import com.niiwoo.tripod.tiancheng.response.common.TianchengUapResponse;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.exception.ExceptionUtils;
import org.joda.time.DateTime;
import org.springframework.amqp.AmqpException;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;

import java.math.BigDecimal;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;

/**
 * @Description:
 * @Author:LiJian
 * @Date:2017/11/7
 */
@Slf4j
@Service(version = "1.0.0")
public class UserCreditDubboServiceImpl implements UserCreditDubboService {

    @Autowired
    private UserCreditService creditLocalService;

    @Autowired
    private UserBlackListLocalService blackListLocalService;

    @Autowired
    private LibraLoanLimitService libraLoanLimitService;

    @Autowired
    private TianchengDataService tianchengDataService;

    @Autowired
    private SnowflakeIdWorker snowflakeIdWorker;

    @Autowired
    private UserImageFileService imageFileService;

    @Autowired
    private RabbitTemplate rabbitTemplate;

    @Autowired
    private IMService imService;

    @Autowired
    private UserIdentityService identityService;

    @Autowired
    private UserDataService userDataService;

    @Autowired
    private TianchengQuantizationService tianchengQuantizationService;

    @Autowired
    private PrivacyMasks privacyMasks;

    @Autowired
    private AuthenticationRecordLocalService authenticationRecordLocalService;

    @Reference(version = "1.0.0")
    private ProjectCommonDubboService projectCommonDubboService;

    @Reference(version = "1.0.0")
    private AccountDubboService accountDubboService;

    @Reference(version = "1.0.0")
    private BankCardDubboService bankCardDubboService;

    @Reference(version = "1.0.0")
    private TradeConfigDubboService tradeConfigDubboService;


    @Override
    public LaunchSpeedLoanCreditDTO launchSpeedLoanCredit(LaunchSpeedLoanCreditRequestDTO creditRequest) {
        log.info("授信反欺诈请求,userId:{}, creditRequest:{}", creditRequest.getUserId(), JSON.toJSONString(creditRequest));
        String userId = creditRequest.getUserId();
        LaunchSpeedLoanCreditDTO launchSpeedLoanCreditDTO = new LaunchSpeedLoanCreditDTO();
        launchSpeedLoanCreditDTO.setFailCode(0);
        launchSpeedLoanCreditDTO.setCreditOvertime(0);
        // 获取系统配置
        List<TradeConfigEnum> enumList = new ArrayList<>();
        enumList.add(TradeConfigEnum.SESAMEAUTHORIZATIONSTATUS);
        enumList.add(TradeConfigEnum.CREDITOVERTIME);
        enumList.add(TradeConfigEnum.MINACCESSAGE);
        enumList.add(TradeConfigEnum.MAXACCESSAGE);
        enumList.add(TradeConfigEnum.SPEEDBORROWCOUNTRYONOFF);
        enumList.add(TradeConfigEnum.SPEEDBORROWCITYCODE);
        Map<String, String> configMap = tradeConfigDubboService.selectTradeConfigByEmuns(enumList);
        String creditExpireTimeStr = configMap.get(TradeConfigEnum.CREDITOVERTIME.getConfigKey());  // 授信超时时间
        String zhimaSwitch = configMap.get(TradeConfigEnum.SESAMEAUTHORIZATIONSTATUS.getConfigKey()); // 芝麻开关
        String minAccessAge = configMap.get(TradeConfigEnum.MINACCESSAGE.getConfigKey()); // 借款人最低准入年龄
        String maxAccessAge = configMap.get(TradeConfigEnum.MAXACCESSAGE.getConfigKey()); // 借款人最高准入年龄
        String speedLoanCountryOnOff = configMap.get(TradeConfigEnum.SPEEDBORROWCOUNTRYONOFF.getConfigKey()); // 极速借城市开通开关:0.开通(全国开通),1.不开通
        if(StringUtils.isAnyBlank(creditExpireTimeStr, zhimaSwitch, minAccessAge, maxAccessAge, speedLoanCountryOnOff)) {
            throw new BizException("SS11001");
        }
        Integer creditExpireTime = Integer.valueOf(creditExpireTimeStr);
        launchSpeedLoanCreditDTO.setCreditOvertime(creditExpireTime);

        // 自有平台才进行下列判断
        if(PlatformTypeEnum.NIIWOO.getType().equals(creditRequest.getPlatformType())) {
            // 用户授信信息完善判断
            if (!speedLoanCreditDataCheck(userId, zhimaSwitch)) {
                launchSpeedLoanCreditDTO.setFailCode(2);
                return launchSpeedLoanCreditDTO;
            }
            // 借款年龄检测
            IdentityInfo identityInfo = identityService.getByUserId(userId);
            if(identityInfo != null) {
                int age = IdCardUtils.getAgeByIdCard(privacyMasks.decryptPrivacy(identityInfo.getIdCard()));
                if(age < Integer.parseInt(minAccessAge) || age > Integer.valueOf(maxAccessAge)) {
                    log.info("userId:{},授信命中年龄限制", userId);
                    launchSpeedLoanCreditDTO.setFailCode(7);
                    return launchSpeedLoanCreditDTO;
                }
            }
            // 借款城市检测
            if("1".equals(speedLoanCountryOnOff)) {
                String speedLoanCityCode = configMap.get(TradeConfigEnum.SPEEDBORROWCITYCODE.getConfigKey()); // 极速借开放城市
                if(StringUtils.isNotBlank(speedLoanCityCode) && userDataService.checkUserAllowLoanCity(userId, speedLoanCityCode)) {
                    log.info("userId:{},授信命中借款限制", userId);
                    launchSpeedLoanCreditDTO.setFailCode(7);
                    return launchSpeedLoanCreditDTO;
                }
            }
        }

        // 用户黑灰名单判断
        UserBlackList userBlackList = blackListLocalService.getSingleBlackListInfo(userId);
        if (userBlackList != null) {
            launchSpeedLoanCreditDTO.setFailCode(5);
            return launchSpeedLoanCreditDTO;
        }

        // 用户授信限制
        UserLibraLoanLimit userLibraLoanLimit = libraLoanLimitService.getUserLibraLoanLimit(userId, ProductTypeEnum.SPEED_LOAN);
        if (userLibraLoanLimit != null) {
            log.info("userId:{},授信命中天秤授信相关限制", userId);
            launchSpeedLoanCreditDTO.setFailCode(7);
            return launchSpeedLoanCreditDTO;
        }

        // 用户否在授信中判断
        UserCreditProcess userCreditProcess = creditLocalService.getUserCreditProcessByType(userId, CreditEnum.CreditAmountType.SPEED_BORROW.getType());
        if (userCreditProcess != null) {
            Byte antifraudStatus = userCreditProcess.getAntifraudStatus();
            Byte creditStatus = userCreditProcess.getCreditStatus();
            // 反欺诈和授信回调中
            if (CreditEnum.AntiFraudStatus.CALLBACKING.getType().equals(antifraudStatus) || CreditEnum.CreditStatus.CALLBACKING.getType().equals(creditStatus)) {
                // 回调过期时间判断，返回过期
                DateTime startTime = new DateTime(userCreditProcess.getCreditStartTime());
                if (startTime.plusMinutes(creditExpireTime).isAfterNow()) {
                    launchSpeedLoanCreditDTO.setFailCode(4);
                    return launchSpeedLoanCreditDTO;
                }
            }
        }

        // 发起授信反欺诈
        boolean againstFakeResult = this.speedCreditAgainstFakeAFP(userId, zhimaSwitch, creditRequest);
        if (!againstFakeResult) {
            launchSpeedLoanCreditDTO.setFailCode(6);
        }
        return launchSpeedLoanCreditDTO;
    }

    @Override
    public UserSpeedCreditInfoDTO getUserSpeedCreditInfo(String userId) {
        UserSpeedCreditInfoDTO userSpeedCreditInfo = new UserSpeedCreditInfoDTO();
        userSpeedCreditInfo.setCreditStatus(0);
        UserCreditInfo userCreditInfo = creditLocalService.getUserCreditInfoByType(userId, CreditEnum.CreditAmountType.SPEED_BORROW.getType());
        if (userCreditInfo != null) {
            // 授信总额度取授信额度和最大借款额度中的最小值
            List<TradeConfigEnum> enumList = new ArrayList<>();
            enumList.add(TradeConfigEnum.MAXAMOUNT);
            Map<String, String> sysConfig = tradeConfigDubboService.selectTradeConfigByEmuns(enumList);
            BigDecimal maxLoanAmount  = new BigDecimal(sysConfig.get(TradeConfigEnum.MAXAMOUNT.getConfigKey()));
            userSpeedCreditInfo.setCreditTotalAmount(userCreditInfo.getCreditAmount().min(maxLoanAmount));
            userSpeedCreditInfo.setCreditModelType(userCreditInfo.getCreditModelType());
            if (CreditEnum.NeedUpdateStatus.YES.getType() == userCreditInfo.getNeedUpdate().byteValue()) {
                userSpeedCreditInfo.setCreditStatus(3);
            } else {
                userSpeedCreditInfo.setCreditStatus(this.isCreditExpired(userCreditInfo.getCreditTime()) ? 3 : 2);
            }
        }
        UserCreditProcess userCreditProcess = creditLocalService.getUserCreditProcessByType(userId, CreditEnum.CreditAmountType.SPEED_BORROW.getType());
        if (userCreditProcess != null) {
            Byte antifraudStatus = userCreditProcess.getAntifraudStatus();
            Byte creditStatus = userCreditProcess.getCreditStatus();
            // 反欺诈和授信回调中
            if (CreditEnum.AntiFraudStatus.CALLBACKING.getType().equals(antifraudStatus) || CreditEnum.CreditStatus.CALLBACKING.getType().equals(creditStatus)) {
                List<TradeConfigEnum> enumList = new ArrayList<>();
                enumList.add(TradeConfigEnum.CREDITOVERTIME);
                Map<String, String> configMap = tradeConfigDubboService.selectTradeConfigByEmuns(enumList);
                // 授信超时时间
                String creditExpireTimeStr = configMap.get(TradeConfigEnum.CREDITOVERTIME.getConfigKey());
                if(StringUtils.isBlank(creditExpireTimeStr)) {
                    throw new BizException("SS11001");
                }
                // 回调过期时间判断，返回过期
                Integer creditExpireTime = Integer.valueOf(creditExpireTimeStr);
                DateTime startTime = new DateTime(userCreditProcess.getCreditStartTime());
                if (startTime.plusMinutes(creditExpireTime).isBeforeNow()) {
                    userSpeedCreditInfo.setCreditStatus(5);
                }else{
                    userSpeedCreditInfo.setCreditStatus(1);
                }

            }
            // 反欺诈和授信失败
            if (CreditEnum.AntiFraudStatus.FAIL.getType().equals(antifraudStatus) || CreditEnum.CreditStatus.FAIL.getType().equals(creditStatus)) {
                userSpeedCreditInfo.setCreditStatus(4);
            }
        }
        return userSpeedCreditInfo;
    }

    @Override
    public void speedLoanCreditAgainstFakeHandle(AFPCallbackDTO afpCallbackDTO) {
        String userId = afpCallbackDTO.getUserId();
        // 融360反欺诈回调处理
        JSONObject msgObject = JSON.parseObject(afpCallbackDTO.getModelResult());
        String platformType = msgObject.getString("platform_type"); // 平台类型
        int platform = StringUtils.isNotBlank(platformType) ? Integer.valueOf(platformType) : PlatformTypeEnum.NIIWOO.getType(); // 默认你我金融
        String modelResult = afpCallbackDTO.getModelStatus();
        boolean creditFlowStatus = false;
        List<TradeConfigEnum> enumList = new ArrayList<>();
        enumList.add(TradeConfigEnum.SESAMEAUTHORIZATIONSTATUS);
        enumList.add(TradeConfigEnum.HITCREDITANTIFRAUDLIMITDAYS);
        enumList.add(TradeConfigEnum.SOCIALSECURITYEXPIRYDATESETTINGS);
        Map<String, String> sysConfig = tradeConfigDubboService.selectTradeConfigByEmuns(enumList);
        if (ModleResultEnum.ACCEPT.getModelResult().equals(modelResult) || ModleResultEnum.REVIEW.getModelResult().equals(modelResult)) {
            // 通过或者人工审核，发起授信数据回流请求
            CreditDataFlowRequest request = new CreditDataFlowRequest();
            request.setCreditTime(System.currentTimeMillis() * 1000);
            // 芝麻开关
            String zhimaSwitch = sysConfig.get(TradeConfigEnum.SESAMEAUTHORIZATIONSTATUS.getConfigKey());
            if(PlatformTypeEnum.NIIWOO.getType() == platform) {
                if("1".equals(zhimaSwitch)) {
                    request.setCreditType(this.isOldUser(userId) > 0 ? CreditTypeEnum.SECOND_LOAN.getType() : CreditTypeEnum.SPEED_LOAN.getType());
                }else {
                    request.setCreditType(this.isOldUser(userId) > 0 ? CreditTypeEnum.NO_ZHIMA_SECOND_LOAN.getType() : CreditTypeEnum.NO_ZHIMA_SPEED_LOAN.getType());
                }
            }else if(PlatformTypeEnum.RONG360.getType() == platform) {
                if ("1".equals(zhimaSwitch)) {
                    request.setCreditType(this.isOldUser(userId) > 0 ? CreditTypeEnum.RONG360_SECOND_LOAN.getType() : CreditTypeEnum.RONG360_SPEED_LOAN.getType());
                } else {
                    request.setCreditType(this.isOldUser(userId) > 0 ? CreditTypeEnum.R360_NO_ZHIMA_SECOND_LOAN.getType() : CreditTypeEnum.R360_NO_ZHIMA_LOAN.getType());
                }
            }
            request.setSesameSwitch(Integer.valueOf(1));
            String socialSecurityExpiry = sysConfig.get(TradeConfigEnum.SOCIALSECURITYEXPIRYDATESETTINGS.getConfigKey());
            // 填充用户信息
            tianchengDataService.fillSpeedLoanCreditRequest(userId, request, platform, Integer.valueOf(socialSecurityExpiry));
            request.setCallUrl(creditLocalService.createCreditAFPCallback(FunctionCodeEnum.SPEED_LOAN_CREDIT_DATA_FLOW));
            TianchengUapResponse tianchengUapResponse = creditLocalService.callTCCreditFlowData(userId, request);
            if (tianchengUapResponse != null && ModleResultEnum.ACCEPT.getModelResult().equals(tianchengUapResponse.getStatus())) {
                creditFlowStatus = true;
            }
        } else if (ModleResultEnum.REFUSE.getModelResult().equals(modelResult)) {
            // 发欺诈受限添加
            String hitCreditAntifraudLimitDays = sysConfig.get(TradeConfigEnum.HITCREDITANTIFRAUDLIMITDAYS.getConfigKey());
            if (StringUtils.isNotBlank(hitCreditAntifraudLimitDays)) {
                libraLoanLimitService.addLibraLoanLimit(userId, LibraLoanLimitEnum.CREDIT_AGAINST_FAKE, ProductTypeEnum.SPEED_LOAN, Integer.valueOf(hitCreditAntifraudLimitDays));
            }
            // 反欺诈拒绝通知客户端
            this.IMCreditMessagePush(userId, "极速借天秤授信命中授信反欺诈");
        }
        // 更新授信过程状态
        creditLocalService.creditAgainstFakeLocalHandle(userId, afpCallbackDTO.getModelStatus(), creditFlowStatus, platform);
    }

    @Override
    public void speedLoanCreditHandle(SpeedLoanCreditCallbackDTO speedLoanCreditCallback) {
        log.info("授信额度回调处理,userId:{}, callback:{}", speedLoanCreditCallback.getUserId(), JSON.toJSONString(speedLoanCreditCallback));
        String userId = speedLoanCreditCallback.getUserId();
        BigDecimal creditAmount = new BigDecimal(speedLoanCreditCallback.getCreditAmount());
        Integer fastBorrowType = speedLoanCreditCallback.getFastBorrowType();
        List<TradeConfigEnum> enumList = new ArrayList<>();
        enumList.add(TradeConfigEnum.HITCREDITMODELLIMITDAYS);
        enumList.add(TradeConfigEnum.MINAMOUNT);
        Map<String, String> tradeConfig = tradeConfigDubboService.selectTradeConfigByEmuns(enumList);
        String minAmount = tradeConfig.get(TradeConfigEnum.MINAMOUNT.getConfigKey());
        int isDiffer = creditAmount.compareTo(new BigDecimal(minAmount));
        boolean creditStatus = true;
        if (isDiffer < 0) {
            // 授信额度不足，借款限制
            String creditModelLimitDays = tradeConfig.get(TradeConfigEnum.HITCREDITMODELLIMITDAYS.getConfigKey());
            libraLoanLimitService.addLibraLoanLimit(userId, LibraLoanLimitEnum.CREDIT_AMOUNT_LESS, ProductTypeEnum.SPEED_LOAN, Integer.valueOf(creditModelLimitDays));
            creditStatus = false; // 达到限制条件则不成功
        }
        // 首次获取额度或者额度增加发送站内信和极光推送
        creditLocalService.pushSpeedLoanCreditMessage(userId, creditStatus, creditAmount);

        // 更新授信过程状态及授信额度信息
        creditLocalService.speedLoanCreditLocalHandle(userId, creditAmount, fastBorrowType, creditStatus);

        // 融360回调MQ通知
        if(CreditEnum.CreditModelType.RONG360.getType() == fastBorrowType.byteValue() || CreditEnum.CreditModelType.RONG360_FREE_QUALIFICATION.getType() == fastBorrowType.byteValue()) {

        }else { // 平台则通过IM通知授信结果
            this.IMCreditMessagePush(userId, "极速借天秤授信额度完成");
        }

        //推送授信事件给活动系统
        this.pushCreditEventToActivity(userId,creditAmount);

        // 学历认证
        if(fastBorrowType != null && CreditEnum.CreditModelType.EDUCATION.getType() == fastBorrowType.byteValue()) {
            log.info("speedLoanCreditHandle.educationAuth.userId={} start",userId);
            CompletableFuture.runAsync(() -> this.educationAuth(userId));
            log.info("speedLoanCreditHandle.educationAuth.userId={} end",userId);
        }
    }

    //推送授信事件给活动系统
    public void pushCreditEventToActivity(String userId,BigDecimal creditAmount){
        log.info("pushCreditEventToActivity.userId={},creditAmount={}",userId,creditAmount);
        try {
            Date now = new Date();
            CreditEventReqDTO creditEventReqDTO = new CreditEventReqDTO();
            creditEventReqDTO.setUserId(userId);
            creditEventReqDTO.setAmount(creditAmount);
            creditEventReqDTO.setCreditUpdate(now);
            creditEventReqDTO.setUpdateDate(now);
            creditEventReqDTO.setCreditTypeEventEnum(CreditTypeEventEnum.TIANCHENG);
            log.info("pushCreditEventToActivity.userId={},creditEventReqDTO={}",userId,JSON.toJSONString(creditEventReqDTO));
            rabbitTemplate.convertAndSend(BizEventRabbitConstant.Exchange.BIZ_EVENT_DIRECT_EXCHANGE,
                    BizEventRabbitConstant.Key.BIZ_EVENT_CREDIT_KEY,
                    creditEventReqDTO);
        } catch (AmqpException e) {
            log.error("pushCreditEventToActivity.userId={},creditAmount={} error",userId,creditAmount,e);
        }
        log.info("pushCreditEventToActivity.userId={},creditAmount={} end",userId,creditAmount);
    }



    @Override
    public UserCreditDataStatusDTO getUserCreditDataStatusDTO(String userId) {
        return this.getUserCreditDataStatus(userId);
    }

    /**
     * 判断是否是借款老用户（当前至少有一笔已结清的极速借借款）
     *
     * @param userId
     * @return 0:false  1:true
     */
    @Override
    public int isOldUser(String userId) {
        int count = projectCommonDubboService.getSpeedLoanProjectNumByStatus(userId, ProjectStatusEnum.FINISH, null);
        return count > 0 ? 1 : 0;
    }

    /**
     * 是否第二次借款
     *
     * @param userId
     * @return
     */
    @Override
    public boolean isSecondLoan(String userId) {
        return projectCommonDubboService.userIsSecondLoan(userId);
    }

    @Override
    public UserCreditProcessStatusDTO getUserCreditProcessStatus(String userId, CreditEnum.CreditAmountType creditAmountType) {
        UserCreditProcess userCreditProcess = creditLocalService.getUserCreditProcessByType(userId, creditAmountType.getType());
        UserCreditProcessStatusDTO creditProcessStatusDTO = new UserCreditProcessStatusDTO();
        if(userCreditProcess != null) {
            creditProcessStatusDTO.setCreditCaller(userCreditProcess.getCreditCaller());
            creditProcessStatusDTO.setCreditType(userCreditProcess.getCreditType());
            creditProcessStatusDTO.setCreditStatus(userCreditProcess.getCreditStatus());
            creditProcessStatusDTO.setAntifraudStatus(userCreditProcess.getAntifraudStatus());
            creditProcessStatusDTO.setCreditStartTime(userCreditProcess.getCreditStartTime());
            creditProcessStatusDTO.setCreditEndTime(userCreditProcess.getCreditEndTime());
        }else {
            creditProcessStatusDTO.setCreditType(creditAmountType.getType());
            creditProcessStatusDTO.setCreditStatus(CreditEnum.CreditStatus.UNVERIFIED.getType());
            creditProcessStatusDTO.setAntifraudStatus(CreditEnum.AntiFraudStatus.UNVERIFIED.getType());
        }
        return creditProcessStatusDTO;
    }

    @Override
    public void changeCreditNeedUpdate(String userId, CreditEnum.CreditAmountType creditAmountType) {
        log.info("changeCreditNeedUpdate, userId={}, creditAmountType={}", userId, creditAmountType.getType());
        UserCreditInfo userCreditInfo = creditLocalService.getUserCreditInfoByType(userId, creditAmountType.getType());
        if(userCreditInfo != null) {
            userCreditInfo = new UserCreditInfo();
            userCreditInfo.setUserId(userId);
            userCreditInfo.setCreditType(creditAmountType.getType());
            userCreditInfo.setNeedUpdate(CreditEnum.NeedUpdateStatus.YES.getType());
            creditLocalService.updateUserCreditInfo(userCreditInfo);
        }
    }

    /**
     * 判断授信是否过期
     *
     * @param creditDate
     * @return
     */
    private boolean isCreditExpired(Date creditDate) {
        DateTime creditTime = new DateTime(creditDate).withTimeAtStartOfDay();
        // 获取授信过期天数
        List<TradeConfigEnum> enumList = new ArrayList<>();
        enumList.add(TradeConfigEnum.CREDITOVERDUE);
        Map<String, String> creditOverdueConfig = tradeConfigDubboService.selectTradeConfigByEmuns(enumList);
        String expireDaysStr = creditOverdueConfig.get(TradeConfigEnum.CREDITOVERDUE.getConfigKey());
        if(StringUtils.isBlank(expireDaysStr)) {
            return false;
        }
        int expireDays = Integer.parseInt(expireDaysStr);
        if (creditTime.plusDays(expireDays).isBeforeNow()) {
            return true;
        }
        return false;
    }

    /**
     * 极速借用户资料认证判断
     *
     * @param userId
     * @param zhimaSwitch
     * @return
     */
    private boolean speedLoanCreditDataCheck(String userId, String zhimaSwitch) {

        UserCreditDataStatusDTO userCreditDataStatus = this.getUserCreditDataStatus(userId);
        // 个人信息
        if (UserDataStatusEnum.PersonInfoStatus.COMPLETE.getStatus() != userCreditDataStatus.getPersonInfoStatus().byteValue()) {
            return false;
        }
        // 是否开通借款账户
        if (!UserDataStatusEnum.OpenBankAccountStatus.PASS_BIND.getStatus().equals(userCreditDataStatus.getOpenBankAccountStatus())) {
            return false;
        }
        // 芝麻信用
        if ("1".equals(zhimaSwitch) && !UserDataStatusEnum.ZhimaCreditStatus.PASS_APPLY.getStatus().equals(userCreditDataStatus.getZhimaCreditStatus())) {
            return false;
        }
        // 手机运营商认证
        if (!(UserDataStatusEnum.PhoneOperatorStatus.ALREADY_CREDIT.getStatus().equals(userCreditDataStatus.getPhoneOperatorStatus())||
                UserDataStatusEnum.PhoneOperatorStatus.GETSUCCESS.getStatus().equals(userCreditDataStatus.getPhoneOperatorStatus()))) {
            return false;
        }

        return true;
    }

    /**
     * 发起授信反欺诈
     * @param userId
     * @param zhimaSwitch
     * @param creditRequest
     * @return
     */
    private boolean speedCreditAgainstFakeAFP(String userId, String zhimaSwitch, LaunchSpeedLoanCreditRequestDTO creditRequest){
        BankCardDTO bankCardDTO = bankCardDubboService.getUserBankCardInfo(userId);
        // 发起极速借授信反欺诈
        LoanAmountAgainsFakeRequest request = new LoanAmountAgainsFakeRequest();
        request.setTransNo(String.valueOf(snowflakeIdWorker.nextId()));
        request.setTransDate(new Date());
        request.setUser_id(String.valueOf(userId));
        request.setIdtype("0");
        request.setBank_cart(bankCardDTO.getBankAccountNo());
        request.setReasonno("01");
        request.setRequest_type(this.isSecondLoan(userId) ? "100" : "1"); // 如果第二次借款授信用控模型
        request.setSource(creditRequest.getCaller());
        request.setLoan_time(0L);
        request.setPlatform_type(creditRequest.getPlatformType());
        request.setToken_id(""); // 同盾传空值
        request.setWeb_url(""); // 同盾传空值
        request.setExt_cutype(this.isOldUser(userId));
        request.setNotify_server_url(creditLocalService.createAFPCallbackUrl("1".equals(zhimaSwitch) ? FunctionCodeEnum.LIBRA_FRAUD_CREDIT_OLD : FunctionCodeEnum.LIBRA_FRAUD_NO_ZHIMA_CREDIT_OLD));
        tianchengDataService.fillUserCreditAgainsFakeInfo(userId, request); // 填充用户数据
        AgainstFakeResponse againstFakeResponse = creditLocalService.callTCSpeedCreditAgainstFakeAFP(userId, zhimaSwitch, request);
        Boolean againstFakeResult = false;
        if (againstFakeResponse != null && ModleResultEnum.ACCEPT.getModelResult().equals(againstFakeResponse.getStatus())) {
            againstFakeResult = true;
        }
        // 反欺诈过程存储
        CreditDeviceInfo creditDeviceInfo = new CreditDeviceInfo();
        BeanUtils.copyProperties(creditRequest, creditDeviceInfo);
        creditLocalService.localLaunchSpeedLoanCredit(userId, creditRequest.getCaller(), creditDeviceInfo, againstFakeResult);

        return againstFakeResult;
    }

    /**
     * 获取极速借资料状态
     *
     * @param userId
     * @return
     */
    private UserCreditDataStatusDTO getUserCreditDataStatus(String userId) {
        // 获取社保，运营商过期时间
        List<TradeConfigEnum> enumList = new ArrayList<>();
        enumList.add(TradeConfigEnum.MOBILESERVICEPROVIDERPWDAUTHORIZEDPERIOD);
        enumList.add(TradeConfigEnum.SOCIALSECURITYEXPIRYDATESETTINGS);
        enumList.add(TradeConfigEnum.OCRSCANIDCARDSWITCH);
        enumList.add(TradeConfigEnum.CREDITCARDCERTIFICATIONPERIOD);
        Map<String, String> tradeConfig = tradeConfigDubboService.selectTradeConfigByEmuns(enumList);
        String mobileServicePeriod = tradeConfig.get(TradeConfigEnum.MOBILESERVICEPROVIDERPWDAUTHORIZEDPERIOD.getConfigKey());
        String socialSecurityExpiry = tradeConfig.get(TradeConfigEnum.SOCIALSECURITYEXPIRYDATESETTINGS.getConfigKey());
        String creditcardExpiry = tradeConfig.get(TradeConfigEnum.CREDITCARDCERTIFICATIONPERIOD.getConfigKey());
        if (StringUtils.isAnyBlank(mobileServicePeriod, socialSecurityExpiry)) {
            throw new BizException("SS11001");
        }
        UserCreditDataStatusDTO userCreditDataStatus = creditLocalService.getUserCreditDataStatus(userId, Integer.valueOf(mobileServicePeriod), Integer.valueOf(socialSecurityExpiry), Integer.valueOf(creditcardExpiry));
        // 借款账户激活状态判断
        List<AccountBaseResponse> accountBaseResponseList = accountDubboService.listNiiwooAccountByUserId(userId);
        if (CollectionUtils.isNotEmpty(accountBaseResponseList)) {
            Optional<AccountBaseResponse> accountBaseResponseOptional = accountBaseResponseList.stream().
                    filter(accout -> UserRoleEnum.BORROWERS.getValue().equals(accout.getAccountRole())).
                    filter(accout -> AccountActiveEnum.ACTIVATED.getValue().equals(accout.getImportUserActiva()))
                    .findFirst();
            userCreditDataStatus.setOpenBankAccountStatus(accountBaseResponseOptional.isPresent() ? UserDataStatusEnum.OpenBankAccountStatus.PASS_BIND.getStatus()
                    : UserDataStatusEnum.OpenBankAccountStatus.NOT_ACTIVE.getStatus());
        }
        // OCR开关配置
        Byte ocrScanSwitch = Byte.valueOf(tradeConfig.get(TradeConfigEnum.OCRSCANIDCARDSWITCH.getConfigKey()));
        userCreditDataStatus.setOCRScanSwitch(ocrScanSwitch);
        // OCR关闭的时候，给出手持照上传状态
        if (0 == ocrScanSwitch.byteValue()) {
            UserImageFile imageFile = imageFileService.getByType(userId, UserImgTypeEnum.IDCARD_IMAGE, UserImgTypeEnum.IDCARD_HAND_IMAGE);
            userCreditDataStatus.setImgUploadStatus((byte) (imageFile != null ? 1 : 0));
        }
        return userCreditDataStatus;
    }

    public void educationAuth(String userId){
        log.info("educationAuth.userId={} start",userId);
        try {
            EducationQueryResponse educationQueryResponse = this.queryEducation(userId);
            if(educationQueryResponse==null){
                return;
            }

            String educationDegree = educationQueryResponse.getEducationDegree();
            if(StringUtils.isEmpty(educationDegree)){
                return;
            }

            EducationMatchEnum educationMatchEnum = EducationMatchEnum.enumOf(educationDegree);
            log.info("educationAuth.userId={},educationMatchEnum={}",userId,JSON.toJSONString(educationMatchEnum));
            userDataService.updateEducationInfo(userId,educationMatchEnum.getUserEduLevelEnum(),UserPersonalEnum.EducationAuthStatusEnum.AUTH,new Date());
            log.info("educationAuth.userId={} end",userId);
        } catch (Exception e) {
            log.error("educationAuth.userId={} error",userId,e);
        }
    }

    @Override
    public UserCreditInfoDTO getUserCreditInfoByType(String userId) {
        UserCreditInfo userCreditInfo = creditLocalService.getUserCreditInfoByType(userId, CreditEnum.CreditAmountType.SPEED_BORROW.getType());
        if(userCreditInfo == null){
            return null;
        }
        UserCreditInfoDTO userCreditInfoDTO = new UserCreditInfoDTO();
        userCreditInfoDTO.setId(userCreditInfo.getId());
        userCreditInfoDTO.setUserId(userCreditInfo.getUserId());
        userCreditInfoDTO.setCreditAmount(userCreditInfo.getCreditAmount());
        userCreditInfoDTO.setCreditType(userCreditInfo.getCreditType());
        userCreditInfoDTO.setCreditModelType(userCreditInfo.getCreditModelType());
        userCreditInfoDTO.setNeedUpdate(userCreditInfo.getNeedUpdate());
        userCreditInfoDTO.setCreditTime(userCreditInfo.getCreditTime());
        return userCreditInfoDTO;
    }



    public EducationQueryResponse queryEducation(String userId){
        IdentityInfo identityInfo = identityService.getByUserId(userId);
        log.info("UserCreditDubboServiceImpl.queryEducation.userId={},identityInfo={}",userId,JSON.toJSONString(identityInfo));
        if(identityInfo==null){
            return null;
        }

        EducationQueryRequest educationQueryRequest = new EducationQueryRequest();
        educationQueryRequest.setIdentityCard(privacyMasks.decryptPrivacy(identityInfo.getIdCard()));
        educationQueryRequest.setRealName(identityInfo.getName());
        CompletableFuture<EducationQueryResponse> completableFuture = tianchengQuantizationService.queryEducation(educationQueryRequest);
        EducationQueryResponse educationQueryResponse = FutureResponses.get(completableFuture);
        log.info("UserCreditDubboServiceImpl.queryEducation.userId={},educationQueryResponse={}",userId,JSON.toJSONString(educationQueryResponse));
        return educationQueryResponse;
    }

    /*public void queryEducation(String userId){
        EducationQueryResponse educationQueryResponse = null;
        try {
            EducationQueryRequest educationQueryRequest = new EducationQueryRequest();
            educationQueryRequest.setIdentityCard("411522199101014510");
            educationQueryRequest.setRealName("徐亚辉");
            educationQueryRequest.setQuertType("0"); //查询模式（0：不强制查库 1：强制查库）
            CompletableFuture<EducationQueryResponse> completableFuture = tianchengQuantizationService.queryEducation(educationQueryRequest);
            educationQueryResponse = completableFuture.get();
            log.info("UserCreditDubboServiceImpl.queryEducation.userId={},educationQueryResponse={}",userId,JSON.toJSONString(educationQueryResponse));
        } catch (Exception e) {
            log.info("UserCreditDubboServiceImpl.queryEducation.userId={}",userId,e);
        }
    }*/

    private void IMCreditMessagePush(String userId, String message) {
        PushCommonNotifyMessageRequest messageRequest = new PushCommonNotifyMessageRequest();
        messageRequest.setFrom(1L);
        messageRequest.setReceiverId(userId);
        Map<String,Object> contentMap = new HashMap<>();
        contentMap.put("msgType", 10003);
        contentMap.put("msg", message);
        messageRequest.setContent(contentMap);
        try {
            imService.pushCommonNotifyMessage(messageRequest);
        } catch (Exception e) {
            log.error("userI:{},通过IM通知授信结果失败,原因:{}", userId, e);
        }
    }


    @Override
    public UserCreditInfoDTO findCreditAmount(String userId, CreditEnum.CreditAmountType creditAmountType) {
        UserCreditInfo userCreditInfo =  creditLocalService.getUserCreditInfoByType(userId,creditAmountType.getType());
        UserCreditInfoDTO userCreditInfoDTO = new UserCreditInfoDTO();
        if(userCreditInfo != null){
            userCreditInfoDTO.setId(userCreditInfo.getId());
            userCreditInfoDTO.setUserId(userCreditInfo.getUserId());
            userCreditInfoDTO.setCreditAmount(userCreditInfo.getCreditAmount());
            userCreditInfoDTO.setCreditType(userCreditInfo.getCreditType());
            userCreditInfoDTO.setCreditModelType(userCreditInfo.getCreditModelType());
            userCreditInfoDTO.setNeedUpdate(userCreditInfo.getNeedUpdate());
        }
        return userCreditInfoDTO;
    }

    @Override
    public MobileRealNameResponseDTO queryMobileRealNameForTiancheng(String realName, String identityCard, String mobilePhone,String userId) {
        MobileRealNameResponseDTO respDTO = new MobileRealNameResponseDTO();
        AuthenticationRecord authenticationRecord = authenticationRecordLocalService.queryUserMobileAuthentication(privacyMasks.encryptPrivacy(mobilePhone),userId);
        if(authenticationRecord != null){
            log.info("用户:{}---实名认证成功结果已缓存本地",userId);
            if("T".equalsIgnoreCase(authenticationRecord.getResult())){
                respDTO.setValidResultStatus("1");
            }
            return respDTO;
        }
        MobileRealNameRequest request = new MobileRealNameRequest();
        request.setIsNew("0");
        request.setMobilePhone(mobilePhone);
        request.setIdentityCard(identityCard);
        request.setRealName(realName);
        boolean isPass = false;
        try {
            request.setIsNew("0");
            CompletableFuture<MobileRealNameResponse> mobileRealNameResponseFuture = tianchengQuantizationService.queryMobileRealName(request);
            MobileRealNameResponse mobileRealNameResponse = mobileRealNameResponseFuture.get(3, TimeUnit.SECONDS);
            if(mobileRealNameResponse != null) {
                log.info("查询天秤实名认证接口返回数据:{}",JSONObject.toJSONString(mobileRealNameResponse));
                respDTO.setValidResultDesc(mobileRealNameResponse.getMessage());
                isPass = "T".equalsIgnoreCase(mobileRealNameResponse.getResult());
                //返回有结果直接存储
                AuthenticationRecord record = new AuthenticationRecord();
                record.setId(snowflakeIdWorker.nextId());
                record.setUserId(userId);
                record.setIdentityCard(StringUtils.isNotBlank(identityCard) ? privacyMasks.encryptPrivacy(identityCard) : "");
                record.setMobilePhone(StringUtils.isNotBlank(mobilePhone) ? privacyMasks.encryptPrivacy(mobilePhone) : "");
                record.setRealName(StringUtils.isNotBlank(realName) ? realName : "");
                record.setReponseData(JSONObject.toJSONString(mobileRealNameResponse));
                record.setResult(mobileRealNameResponse.getResult());
                record.setCreateTime(new Date());
                record.setUpdateTime(new Date());
                authenticationRecordLocalService.insertAuthInfo(record);
                log.info("用户:{}---调用天秤实名认证成功----缓存本地成功",userId);
                // 此行代码可能报异常， 需要放到末尾执行
                if(mobileRealNameResponse.getTimeStamp() != null) {
                    respDTO.setObtainTime(new Date(Long.valueOf(mobileRealNameResponse.getTimeStamp())));
                }
            }
        } catch (Exception e) {
            log.warn("调用天秤考拉接口异常: " + ExceptionUtils.getRootCauseMessage(e));
        }
        // 通过就直接返回了

        if(isPass) {
            respDTO.setValidIdCard(request.getIdentityCard());
            respDTO.setValidMobileNo(request.getMobilePhone());
            respDTO.setValidName(request.getRealName());
            respDTO.setValidResultStatus("1");
            return respDTO;
        }
        return respDTO;
    }
}
